home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------------------
-
- FILE:
- flicker free.c
-
- DESCRIPTION:
- this contains a demonstration of how to use the screen
- buffering library to obtain flicker free drawing.
-
- COPYRIGHT:
- ©1995 Hugo M. Ayala
- ©1995 Apple Computer Inc.
-
- CHANGE LOG:
-
- 07/07/95 Hugo first version.
-
- ---------------------------------------------------------------------------------*/
- #include <Types.h>
- #include <Windows.h>
- #include <Dialogs.h>
- #include <DiskInit.h>
- #include <Desk.h>
- #include <Memory.h>
- #include <Events.h>
- #include <Errors.h>
- #include <Fonts.h>
- #include <Menus.h>
- #include <SegLoad.h>
- #include <ToolUtils.h>
- #include <Quickdraw.h>
- #include <GestaltEqu.h>
- #include <Timer.h>
-
- #include "GXExceptions.h"
-
- #include "math routines.h"
- #include "graphics routines.h"
- #include "graphics macintosh.h"
- #include "graphics toolbox.h"
-
- #include "screen buffering.h"
-
- #define rAboutAlert 128
- #define rPleaseInstallGX 129
- #define rTestResult 130
-
- #define rMenuBar 128
- #define rDocWindow 128
-
- #define rApple 128
- #define rFile 129
- #define rDrawing 130
-
- #define rAbout 1
- #define rOneParticle 1
- #define rTenParticles 2
- #define rFiftyParticles 3
-
- #define rFullWindowBuffering 5
- #define rNoWindowBuffering 6
- #define rHalfAndHalf 7
-
- #define rRefresRateTest 9
-
- /*---------------------------------------------------------------------------------
- Some Prototypes.
- ---------------------------------------------------------------------------------*/
- static void Initialize( void );
- static void EventLoop( void );
- /*---------------------------------------------------------------------------------
- The application Globals.
- ---------------------------------------------------------------------------------*/
- struct ApplicationGlobals {
-
- short bufferingmethod;
-
- long sleeptime;
-
- WindowPtr window;
- gxViewPort parent;
- gxViewPort view;
-
- viewPortBuffer buffer;
-
- gxShape scene;
- gxShape erase;
-
- Handle shapeList;
- Handle speedList;
-
- };
-
- struct ApplicationGlobals global;
- /*---------------------------------------------------------------------------------
- main
- ---------------------------------------------------------------------------------*/
- void main()
- {
- long version;
-
- InitGraf((Ptr) &qd.thePort );
- InitFonts();
- InitWindows();
- InitMenus();
- InitDialogs( 0L );
- InitCursor();
-
- if( Gestalt( gestaltGraphicsVersion, &version ) == noErr )
- {
- Initialize();
- EventLoop();
- }
- else
- {
- (void) Alert( rPleaseInstallGX, nil );
- }
- }
- /*---------------------------------------------------------------------------------
- HandleIdle
- ---------------------------------------------------------------------------------*/
- static void HandleIdle( void )
- {
- long count;
-
- if( count = GetHandleSize( global.speedList ) / sizeof( gxPoint ) )
- {
- long indx;
-
- gxRectangle bounds;
-
- gxShape *shapePtr;
- gxPoint *speedPtr;
-
- bounds.left = bounds.top = 0;
- bounds.right = ff( global.window->portRect.right );
- bounds.bottom = ff( global.window->portRect.bottom );
-
- HLock( global.shapeList ); shapePtr = * (gxShape **) global.shapeList;
- HLock( global.speedList ); speedPtr = * (gxPoint **) global.speedList;
-
- for( indx = 0; indx < count; indx += 1 )
- {
- Fixed radius;
- gxPoint location;
-
- gxRectangle bbox;
-
- GXGetShapeBounds( shapePtr[ indx ], 0, &bbox );
-
- radius = ( bbox.right - bbox.left ) / 2;
-
- location.x = bbox.left + radius;
- location.y = bbox.top + radius;
-
- location.x += speedPtr[ indx ].x;
- location.y += speedPtr[ indx ].y;
-
- if( ( location.x - radius ) < bounds.left && speedPtr[ indx ].x < 0 )
- {
- speedPtr[ indx ].x = -speedPtr[ indx ].x;
- }
-
- if( bounds.right < ( location.x + radius ) && speedPtr[ indx ].x > 0 )
- {
- speedPtr[ indx ].x = -speedPtr[ indx ].x;
- }
-
- check( bounds.left <= location.x && location.x <= bounds.right );
-
- if( ( location.y - radius ) < bounds.top && speedPtr[ indx ].y < 0 )
- {
- speedPtr[ indx ].y = -speedPtr[ indx ].y;
- }
-
- if( bounds.bottom < ( location.y + radius ) && speedPtr[ indx ].y > 0 )
- {
- speedPtr[ indx ].y = -speedPtr[ indx ].y;
- }
-
- check( bounds.top <= location.y && location.y <= bounds.bottom );
-
- GXMoveShapeTo( shapePtr[ indx ], location.x - radius, location.y - radius );
- }
-
- HUnlock( global.speedList );
- HUnlock( global.shapeList );
-
- /* this draws the unbuffered half */
-
- GXDrawShape( global.erase );
- GXDrawShape( global.scene );
-
- /* and this draws the buffered half */
-
- DrawShapeBuffered( global.buffer, global.scene, nil );
- }
- }
- /*---------------------------------------------------------------------------------
- PickFixed
- ---------------------------------------------------------------------------------*/
- static Fixed PickFixed( const Fixed low, const Fixed high )
- {
- Fixed range = high - low;
- short start = Random();
-
- if( start < 0 ) start = -start;
-
- return FixedMultiply( FixRatio( start, 0x7FFF ), range ) + low;
- }
- /*---------------------------------------------------------------------------------
- NewParticleShape
- ---------------------------------------------------------------------------------*/
- static gxShape NewParticleShape( const Fixed radius )
- {
- #define particlepoints 5
-
- gxPolar round;
- long indx;
-
- struct {
- long contours;
- long vectors;
- long control;
-
- gxPoint points[ particlepoints ];
- } path;
-
- path.contours = 1;
- path.vectors = particlepoints;
- path.control = 0xFFFFFFFF;
-
- round.radius = radius;
- round.angle = 0;
-
- for( indx = 0; indx < particlepoints; indx += 1 )
- {
- PolarToPoint( &round, & path.points[ indx ] );
- round.angle += ff( 360 ) / particlepoints;
- }
-
- #undef particlepoints
-
- return GXNewPaths((gxPaths *) &path );
- }
- /*---------------------------------------------------------------------------------
- SetShapeRandomColor
- ---------------------------------------------------------------------------------*/
- static void SetShapeRandomColor( gxShape sh )
- {
- gxColor color;
-
- color.space = gxHSVSpace;
- color.profile = nil;
- color.element.hsv.hue = (gxColorValue) Random();
- color.element.hsv.saturation = 0xFFFF;
- color.element.hsv.value = 0xFFFF;
-
- GXSetShapeColor( sh, &color );
- }
- /*---------------------------------------------------------------------------------
- SetWindowBuffering
- ---------------------------------------------------------------------------------*/
- static void SetWindowBuffering( const short which )
- {
- gxShape bufferclip;
- gxShape windowclip;
-
- gxRectangle bufferbox;
- gxRectangle windowbox;
-
- Rect bounds = global.window->portRect;
-
- switch( which )
- {
- case rFullWindowBuffering:
- bufferbox.left = ff( bounds.left );
- bufferbox.top = ff( bounds.top );
- bufferbox.right = ff( bounds.right );
- bufferbox.bottom = ff( bounds.bottom );
- windowbox.left =
- windowbox.top =
- windowbox.right =
- windowbox.bottom = 0;
- break;
- case rNoWindowBuffering:
- bufferbox.left =
- bufferbox.top =
- bufferbox.right =
- bufferbox.bottom = 0;
- windowbox.left = ff( bounds.left );
- windowbox.top = ff( bounds.top );
- windowbox.right = ff( bounds.right );
- windowbox.bottom = ff( bounds.bottom );
- break;
-
- default:
- case rHalfAndHalf:
- bufferbox.left = ff( bounds.left );
- bufferbox.top = ff( bounds.top );
- bufferbox.right = ff( ( bounds.right + bounds.left ) / 2 );
- bufferbox.bottom = ff( bounds.bottom );
- windowbox.left = bufferbox.right;
- windowbox.top = bufferbox.top;
- windowbox.right = ff( bounds.right );
- windowbox.bottom = bufferbox.bottom;
- break;
- }
-
- bufferclip = GXNewRectangle( &bufferbox );
- windowclip = GXNewRectangle( &windowbox );
-
- GXSetViewPortClip( global.view, windowclip );
- UpdateViewPortWBuffer( global.buffer, bufferclip, nil );
-
- GXDisposeShape( windowclip );
- GXDisposeShape( bufferclip );
-
- global.bufferingmethod = which;
- }
- /*---------------------------------------------------------------------------------
- SetSceneParticleCount
- ---------------------------------------------------------------------------------*/
- static void SetSceneParticleCount( const long newcount )
- {
- gxShape *shapePtr;
- gxPoint *speedPtr;
-
- long indx;
-
- /* delete all of the shapes currently in the scene */
- /* this makes room for the new shape that we're going to make */
-
- GXSetPictureParts( global.scene, 1, gxSelectToEnd, 0, nil, nil, nil, nil );
-
- SetHandleSize( global.shapeList, newcount * sizeof( gxShape ) );
- nrequire( MemError(), ResizeShapeListFailed );
-
- SetHandleSize( global.speedList, newcount * sizeof( gxPoint ) );
- nrequire( MemError(), ResizeSpeedListFailed );
-
- HLock( global.shapeList ); shapePtr = * (gxShape **) global.shapeList;
- HLock( global.speedList ); speedPtr = * (gxPoint **) global.speedList;
-
- for( indx = 0; indx < newcount; indx += 1 )
- {
- Fixed radius;
- gxPolar velocity;
-
- gxRectangle bounds;
-
- gxShape particle;
-
- bounds.left = bounds.top = 0;
- bounds.right = ff( global.window->portRect.right );
- bounds.bottom = ff( global.window->portRect.bottom );
-
- #define minimumParticleRadius ff( 5 )
- #define maximumParticleRadius ff( 20 )
-
- radius = PickFixed( minimumParticleRadius, maximumParticleRadius );
-
- particle = NewParticleShape( radius );
-
- GXMoveShapeTo( particle, PickFixed( bounds.left, bounds.right ),
- PickFixed( bounds.top, bounds.bottom ) );
- SetShapeRandomColor( particle );
-
- shapePtr[ indx ] = particle;
-
- velocity.radius = maximumParticleRadius - radius + fixed1/2;
- velocity.angle = PickFixed( ff( 0 ), ff( 360 ) );
-
- PolarToPoint( &velocity, &speedPtr[ indx ] );
-
- #undef minimumParticleRadius
- #undef maximumParticleRadius
- }
-
- GXSetPictureParts( global.scene, 1, gxSelectToEnd, newcount,
- shapePtr, nil, nil, nil );
-
- for( indx = 0; indx < newcount; indx += 1 )
- GXDisposeShape( shapePtr[ indx ] );
-
- HUnlock( global.speedList );
- HUnlock( global.shapeList );
-
- ResizeShapeListFailed: ResizeSpeedListFailed:;
- }
- /*---------------------------------------------------------------------------------
- ReportTestResult
- ---------------------------------------------------------------------------------*/
- static void ReportTestResult( const long count, const long time )
- {
- Str255 countstring;
- Str255 timestring;
-
- NumToString( count, countstring );
- NumToString( time, timestring );
-
- ParamText( countstring, timestring, nil, nil );
- (void) Alert( rTestResult, nil );
- }
- /*---------------------------------------------------------------------------------
- RefreshRateTest
- ---------------------------------------------------------------------------------*/
- static void RefreshRateTest( void )
- {
- gxRectangle bounds;
- gxShape sh;
-
- Point size;
-
- long count;
- long ticks;
-
- #define durationInTicks (5*60)
-
- size.h = ( global.window->portRect.right - global.window->portRect.left ) >> 2;
- size.v = ( global.window->portRect.bottom - global.window->portRect.top ) >> 2;
-
- bounds.left = ff( size.h );
- bounds.top = ff( size.v );
- bounds.right = ff( size.h * 3 );
- bounds.bottom = ff( size.v * 3 );
-
- sh = GXNewRectangle( &bounds );
- SetShapeRandomColor( sh );
-
- GXSetShapeViewPorts( sh, 1, & global.view );
-
- count = 0;
- ticks = TickCount() + durationInTicks;
-
- do
- {
- GXDrawShape( global.erase );
- GXDrawShape( sh );
-
- DrawShapeBuffered( global.buffer, sh, nil );
-
- count += 1;
-
- } while( TickCount() < ticks );
-
- ReportTestResult( count, durationInTicks / 60 );
-
- #undef durationInTicks
-
- GXDisposeShape( sh );
- }
- /*---------------------------------------------------------------------------------
- HandleDrawingMenu
- ---------------------------------------------------------------------------------*/
- static void HandleDrawingMenu( const short menuitem )
- {
- MenuHandle menuHdl = GetMenuHandle( rDrawing );
-
- switch( menuitem )
- {
- case rOneParticle:
- CheckItem( menuHdl, rOneParticle, true );
- CheckItem( menuHdl, rTenParticles, false );
- CheckItem( menuHdl, rFiftyParticles, false );
- SetSceneParticleCount( 1 );
- break;
- case rTenParticles:
- CheckItem( menuHdl, rOneParticle, false );
- CheckItem( menuHdl, rTenParticles, true );
- CheckItem( menuHdl, rFiftyParticles, false );
- SetSceneParticleCount( 10 );
- break;
- case rFiftyParticles:
- CheckItem( menuHdl, rOneParticle, false );
- CheckItem( menuHdl, rTenParticles, false );
- CheckItem( menuHdl, rFiftyParticles, true );
- SetSceneParticleCount( 50 );
- break;
-
- /* ----------------------- */
-
- case rFullWindowBuffering:
- CheckItem( menuHdl, rFullWindowBuffering, true );
- CheckItem( menuHdl, rNoWindowBuffering, false );
- CheckItem( menuHdl, rHalfAndHalf, false );
- SetWindowBuffering( rFullWindowBuffering );
- break;
- case rNoWindowBuffering:
- CheckItem( menuHdl, rFullWindowBuffering, false );
- CheckItem( menuHdl, rNoWindowBuffering, true );
- CheckItem( menuHdl, rHalfAndHalf, false );
- SetWindowBuffering( rNoWindowBuffering );
- break;
- case rHalfAndHalf:
- CheckItem( menuHdl, rFullWindowBuffering, false );
- CheckItem( menuHdl, rNoWindowBuffering, false );
- CheckItem( menuHdl, rHalfAndHalf, true );
- SetWindowBuffering( rHalfAndHalf );
- break;
-
- /* ----------------------- */
-
- case rRefresRateTest:
- RefreshRateTest();
- break;
- }
- }
- /*---------------------------------------------------------------------------------
- HandleMenuCommand
- ---------------------------------------------------------------------------------*/
- static void HandleMenuCommand( const long command )
- {
-
- short menuid;
- short menuitem;
-
- menuid = HiWord( command );
- menuitem = LoWord( command );
-
- switch( menuid )
- {
- case rApple:
- switch( menuitem )
- {
- case rAbout:
- (void) Alert( rAboutAlert, nil );
- break;
-
- default:
- {
- Str255 daname;
- short darefnum;
-
- GetMenuItemText( GetMenuHandle( rApple ), menuitem, daname );
- darefnum = OpenDeskAcc( daname );
- }
- break;
- }
- break;
-
- case rFile:
- ExitToShell();
- break;
-
- case rDrawing:
- HandleDrawingMenu( menuitem );
- break;
- }
-
- HiliteMenu( 0 ); // unselect the menu that was selected
-
- }
- /*---------------------------------------------------------------------------------
- HandleMouseDown
- ---------------------------------------------------------------------------------*/
- static void HandleGrowWindow( WindowPtr window, EventRecord *event )
- {
- long growresult;
-
- Rect param;
-
- param = qd.screenBits.bounds;
- param.left = 40;
- param.top = 40;
-
- if( growresult = GrowWindow( window, event->where, ¶m ) )
- {
- SizeWindow( window, LoWord( growresult ), HiWord( growresult ), true );
- }
- }
- /*---------------------------------------------------------------------------------
- HandleMouseDown
- ---------------------------------------------------------------------------------*/
- static void HandleMouseDown( EventRecord *eventPtr )
- {
- short part;
- WindowPtr window;
-
- part = FindWindow( eventPtr->where, &window );
-
- switch( part )
- {
- case inMenuBar:
- HandleMenuCommand( MenuSelect( eventPtr->where ) );
- break;
-
- case inSysWindow:
- SystemClick( eventPtr, window );
- break;
-
- case inContent:
- break;
-
- case inDrag:
- DragWindow( window, eventPtr->where, &qd.screenBits.bounds );
- break;
-
- case inGoAway:
- if( TrackGoAway( window, eventPtr->where ) )
- ExitToShell();
- break;
-
- case inGrow:
- HandleGrowWindow( window, eventPtr );
- SetWindowBuffering( global.bufferingmethod );
- break;
-
- case inZoomIn:
- case inZoomOut:
- if( TrackBox( window, eventPtr->where, part ) )
- {
- SetPort( window );
- ZoomWindow( window, part, false );
- SetWindowBuffering( global.bufferingmethod );
- }
- break;
- }
- }
- /*---------------------------------------------------------------------------------
- HandleEvent
- ---------------------------------------------------------------------------------*/
- static void HandleEvent( EventRecord *eventPtr )
- {
-
- switch( eventPtr->what )
- {
- case mouseDown:
- HandleMouseDown( eventPtr );
- break;
-
- case keyDown:
- if( ( eventPtr->modifiers & cmdKey ) && // check for a menu command key equivalent
- ( ' ' <= ( eventPtr->message & charCodeMask ) ) ) // but don't filter cmd-arrow keys
- {
- HandleMenuCommand( MenuKey( eventPtr->message & charCodeMask ) );
- }
- break;
-
- case diskEvt:
- if( ( eventPtr->message >> 16 ) != noErr )
- {
- Point where = { 100, 100 };
-
- DIBadMount( where, eventPtr->message );
- }
- break;
-
- case updateEvt:
- if((WindowPtr) eventPtr->message == global.window )
- {
- SetPort( global.window );
-
- BeginUpdate( global.window );
- /* we want to draw the whole window, not just the update rgn */
- EndUpdate( global.window );
-
- HandleIdle();
- }
- break;
-
- case osEvt:
- switch( eventPtr->message >> 24 ) // look at the top byte
- {
- case suspendResumeMessage:
- if( eventPtr->message & resumeFlag )
- global.sleeptime = 0;
- else
- global.sleeptime = 60;
- break;
- }
- break;
-
- case nullEvent:
- default:
- HandleIdle();
- break;
-
- }
- }
- /*---------------------------------------------------------------------------------
- Initialize
- ---------------------------------------------------------------------------------*/
- static void Initialize( void )
- {
- Handle menubar;
- gxColor backcolor;
-
- GXEnterGraphics();
-
- global.sleeptime = 0;
-
- require( menubar = GetNewMBar( rMenuBar ), GetMenuBarFailed );
- SetMenuBar( menubar );
- AppendResMenu( GetMenuHandle( rApple ), 'DRVR' ); // create the apple menu
- DrawMenuBar();
-
- require( global.window = GetNewCWindow( rDocWindow, nil, (WindowPtr) (-1) ),
- GetWindowFailed );
-
- global.parent = GXNewWindowViewPort( global.window );
- global.view = GXNewViewPort( GXGetViewPortViewGroup( global.parent ) );
- GXSetViewPortParent( global.view, global.parent );
-
- backcolor.space = gxRGBSpace;
- backcolor.profile = nil;
- backcolor.element.rgb.red =
- backcolor.element.rgb.green =
- backcolor.element.rgb.blue = 0x0000;
-
- require( global.buffer = NewViewPortWBuffer( global.window, global.view, &backcolor ),
- NewViewPortBufferFailed );
-
- GXSetViewPortDither( global.view, 4 );
- SetViewPortWBufferDither( global.buffer, 4 );
-
- global.scene = GXNewShape( gxPictureType );
- GXSetShapeViewPorts( global.scene, 1, &global.view );
-
- global.erase = GXNewShape( gxFullType );
- GXSetShapeViewPorts( global.erase, 1, &global.view );
-
- require( global.shapeList = NewHandle( 0 ), ShapeListFailed );
- require( global.speedList = NewHandle( 0 ), SpeedListFailed );
-
- HandleDrawingMenu( rFiftyParticles );
- HandleDrawingMenu( rHalfAndHalf );
-
- return;
-
- SpeedListFailed: ShapeListFailed:
- NewViewPortBufferFailed: GetWindowFailed: GetMenuBarFailed:
- ExitToShell();
- }
- /*---------------------------------------------------------------------------------
- EventLoop
- ---------------------------------------------------------------------------------*/
- static void EventLoop( void )
- {
- EventRecord event;
-
- for(;;)
- {
- if( WaitNextEvent( everyEvent, &event, global.sleeptime, nil ) )
- {
- HandleEvent( &event );
- }
- else
- {
- HandleIdle();
- }
- }
- }
-